﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using DataModels.Models;
using System.Text.RegularExpressions;
using DataModels.Common;
using DataModels;
using DataModels.Enumerations;
using GenericTools;
using GenericTools.Models;
using System.Data.Common;
using System.Data;

namespace GenericTools.OptionBPlus
{
    public class ANCFormValidator : FormValidator
    {
        #region Constants
        //private const int ANC_MTUHA_REPORT_ID = 1;
        private const int MTUHA_REPORT_SECTION_1 = 1;
        private const int MTUHA_REPORT_SECTION_2 = 2;
        private const int MTUHA_REPORT_SECTION_3 = 3;
        private const int MTUHA_REPORT_SECTION_4 = 4;
        private const int MTUHA_REPORT_SECTION_5 = 5;
        private const int MTUHA_REPORT_SECTION_6 = 6;
        private const int MTUHA_REPORT_SECTION_7 = 7;
        private const int MTUHA_REPORT_SECTION_8 = 8;
        private const int MTUHA_REPORT_SECTION_9 = 9;
        private const int MTUHA_REPORT_SECTION_10 = 10;

        public const string SETTINGS_KEY_ANC_MTUHA_REPORT_KEYWORDS = "ANC_MTUHA_REPORT_KEYWORDS";
        public const string DEFAULT_ANC_MTUHA_REPORT_KEYWORDS = "ANC|ANC1";

        public const string SETTINGS_KEY_CLASSIC_ANC_MTUHA_REPORT_KEYWORDS = "ClassicANCMtuhaReportKeywords";
        public const string DEFAULT_ANC_CLASSIC_MTUHA_REPORT_KEYWORDS = "K1C20,K1J20|K2C20,K2J20|K3C20,K3J20|K4C20,K4J20|K5C20,K5J20|K6C20,K6J20|K7C20,K7J20|K8C20,K8J20|K9C20,K9J20|K10C20,K10J20";

        public const string MTUHA_ANC_CLASSICAL_K1_UNDER_20 = "MTUHA_ANC_CLASSICAL_K1_UNDER_20";
        public const string MTUHA_ANC_CLASSICAL_K1_ABOVE_20 = "MTUHA_ANC_CLASSICAL_K1_ABOVE_20";
        
        public const string MTUHA_ANC_CLASSICAL_K2_UNDER_20 = "MTUHA_ANC_CLASSICAL_K2_UNDER_20";
        public const string MTUHA_ANC_CLASSICAL_K2_ABOVE_20 = "MTUHA_ANC_CLASSICAL_K2_ABOVE_20";
        
        public const string MTUHA_ANC_CLASSICAL_K3_UNDER_20 = "MTUHA_ANC_CLASSICAL_K3_UNDER_20";
        public const string MTUHA_ANC_CLASSICAL_K3_ABOVE_20 = "MTUHA_ANC_CLASSICAL_K3_ABOVE_20";

        public const string MTUHA_ANC_CLASSICAL_K4_UNDER_20 = "MTUHA_ANC_CLASSICAL_K4_UNDER_20";
        public const string MTUHA_ANC_CLASSICAL_K4_ABOVE_20 = "MTUHA_ANC_CLASSICAL_K4_ABOVE_20";

        public const string MTUHA_ANC_CLASSICAL_K5_UNDER_20 = "MTUHA_ANC_CLASSICAL_K5_UNDER_20";
        public const string MTUHA_ANC_CLASSICAL_K5_ABOVE_20 = "MTUHA_ANC_CLASSICAL_K5_ABOVE_20";

        #region Old and new versions of MTUHA report
        public const string MTUHA_ANC_CLASSICAL_K5_UNDER_20v1 = "MTUHA_ANC_CLASSICAL_K5_UNDER_20v1";    // 16 indicators, before Dec 2014
        public const string MTUHA_ANC_CLASSICAL_K5_ABOVE_20v1 = "MTUHA_ANC_CLASSICAL_K5_ABOVE_20v1";

        public const string MTUHA_ANC_CLASSICAL_K5_UNDER_20v2 = "MTUHA_ANC_CLASSICAL_K5_UNDER_20v2";    // 15 indicators after Dec 2014
        public const string MTUHA_ANC_CLASSICAL_K5_ABOVE_20v2 = "MTUHA_ANC_CLASSICAL_K5_ABOVE_20v2";
        #endregion

        public const string MTUHA_ANC_CLASSICAL_K6_UNDER_20 = "MTUHA_ANC_CLASSICAL_K6_UNDER_20";
        public const string MTUHA_ANC_CLASSICAL_K6_ABOVE_20 = "MTUHA_ANC_CLASSICAL_K6_ABOVE_20";

        public const string MTUHA_ANC_CLASSICAL_K7_UNDER_20 = "MTUHA_ANC_CLASSICAL_K7_UNDER_20";
        public const string MTUHA_ANC_CLASSICAL_K7_ABOVE_20 = "MTUHA_ANC_CLASSICAL_K7_ABOVE_20";

        public const string MTUHA_ANC_CLASSICAL_K8_UNDER_20 = "MTUHA_ANC_CLASSICAL_K8_UNDER_20";
        public const string MTUHA_ANC_CLASSICAL_K8_ABOVE_20 = "MTUHA_ANC_CLASSICAL_K8_ABOVE_20";

        public const string MTUHA_ANC_CLASSICAL_K9_UNDER_20 = "MTUHA_ANC_CLASSICAL_K9_UNDER_20";
        public const string MTUHA_ANC_CLASSICAL_K9_ABOVE_20 = "MTUHA_ANC_CLASSICAL_K9_ABOVE_20";

        public const string MTUHA_ANC_CLASSICAL_K10_UNDER_20 = "MTUHA_ANC_CLASSICAL_K10_UNDER_20";
        public const string MTUHA_ANC_CLASSICAL_K10_ABOVE_20 = "MTUHA_ANC_CLASSICAL_K10_ABOVE_20";

        private const int OTHER_DATA_BEFORE_REPORT_INDICATORS_IN_CLASSICAL_FORMAT = 3;
        #endregion

        private List<ANCForm> _SavedForms = null;
        private int classicalReportId = INVALID_REPORT_ID;

        public ANCFormValidator(string message, string phoneNumberOrUsername, SMSReportingFormat format,
            ReportingMode mode, DataInputingMethod inputingMethod = DataInputingMethod.SMS,
            string password = null, bool saveInClassicFormat = false)
            : base(message, phoneNumberOrUsername, format, mode, inputingMethod, password, saveInClassicFormat)
        {
            _SavedForms = new List<ANCForm>();
        }

        protected override bool ValidateReportIndicators(ReportDataSegment reportDataSegment)
        {
            int section = reportDataSegment.SectionNumber;
            List<int> indicators = reportDataSegment.Indicators;

            if (this.error != ReportProcessingError.NO_ERROR) return false;

            ReportProcessingError e = ReportProcessingError.NO_ERROR;
            bool hasError;
            ValidateReportSection(reportDataSegment, out hasError);
            e = this.reportingError.Type;

            if (hasError) error = e;
            return (!hasError);
        }

        protected override bool Insert(ReportDataSegment report, ANCFormMetadata metadata)
        {
            ANCForm form = GetRootANCForm(report, metadata);

            bool found = false;
            switch (report.SectionNumber)
            {
                case MTUHA_REPORT_SECTION_1:
                    found = true;
                    form.C_1 = report.Indicators[0];
                    break;

                case MTUHA_REPORT_SECTION_3:
                    found = true;
                    form.C_3 = report.Indicators[0];
                    break;

                case MTUHA_REPORT_SECTION_7:
                    found = true;
                    form.C_7 = report.Indicators[0];
                    break;

                case MTUHA_REPORT_SECTION_8:
                    found = true;
                    form.C_8 = report.Indicators[0];
                    break;

                case MTUHA_REPORT_SECTION_9:
                    found = true;
                    form.C_9 = report.Indicators[0];
                    break;

                case MTUHA_REPORT_SECTION_10:
                    found = true;
                    form.C_10 = report.Indicators[0];
                    break;
            }

            if (!found)
            {
                if (report.SectionNumber == MTUHA_REPORT_SECTION_2)
                {
                    var sectionInfo = new ANCForm_HudhurioLaKwanza
                    {
                        ANCFormMetadata = metadata,
                        Facility = dbContext.Facilities.Where(f => f.FacCode == this.facilityCode).FirstOrDefault(),
                        ReportDate = DateTime.Parse(string.Format("{0}-{1}-1", this.reportYear, this.reportMonth)),
                        LessThan20 = (report.AgeCategory == MTUHAAgeCategory.UNDER_20_YEARS),

                        C_2a = report.Indicators[0],
                        C_2b = report.Indicators[1],
                        C_2c = report.Indicators[2],
                        C_2d = report.Indicators[3],
                        C_2e = report.Indicators[4],
                        C_2f = report.Indicators[5],
                        C_2g = report.Indicators[6]
                    };
                    dbContext.ANCForm_HudhurioLaKwanza.Add(sectionInfo);
                    form.ANCForm_HudhurioLaKwanza = sectionInfo;
                }

                if (report.SectionNumber == MTUHA_REPORT_SECTION_4)
                {
                    var sectionInfo = new ANCForm_VidokezoVyaHatari
                    {
                        ANCFormMetadata = metadata,
                        Facility = dbContext.Facilities.Where(f => f.FacCode == this.facilityCode).FirstOrDefault(),
                        ReportDate = DateTime.Parse(string.Format("{0}-{1}-1", this.reportYear, this.reportMonth)),
                        LessThan20 = (report.AgeCategory == MTUHAAgeCategory.UNDER_20_YEARS),

                        C_4a = report.Indicators[0],
                        C_4b = report.Indicators[1],
                        C_4c = report.Indicators[2],
                        C_4d = report.Indicators[3],
                        C_4e = report.Indicators[4],
                        C_4f = report.Indicators[5],
                        C_4g = report.Indicators[6],
                        C_4h = report.Indicators[7],
                        C_4i = report.Indicators[8],
                        C_4j = report.Indicators[9],
                        C_4k = report.Indicators[10],
                        C_4l = report.Indicators[11],
                        C_4m = report.Indicators[12],
                        C_4n = report.Indicators[13],
                        C_4o = report.Indicators[14],
                        C_4p = report.Indicators[15],
                        C_4q = report.Indicators[16],
                        C_4r = report.Indicators[17]
                    };
                    dbContext.ANCForm_VidokezoVyaHatari.Add(sectionInfo);
                    form.ANCForm_VidokezoVyaHatari = sectionInfo;
                }

                if (report.SectionNumber == MTUHA_REPORT_SECTION_5)
                {
                    var sectionInfo = new ANCForm_PMTCT
                    {
                        ANCFormMetadata = metadata,
                        Facility = dbContext.Facilities.Where(f => f.FacCode == this.facilityCode).FirstOrDefault(),
                        ReportDate = DateTime.Parse(string.Format("{0}-{1}-1", this.reportYear, this.reportMonth)),
                        LessThan20 = (report.AgeCategory == MTUHAAgeCategory.UNDER_20_YEARS),

                        C_5a = report.Indicators[0],
                        C_5b = report.Indicators[1],
                        C_5c = report.Indicators[2],
                        C_5d = report.Indicators[3],
                        C_5e = report.Indicators[4],
                        C_5f = report.Indicators[5],
                        C_5g = report.Indicators[6],
                        C_5h = report.Indicators[7],
                        C_5i = report.Indicators[8],
                        C_5j = report.Indicators[9],
                        C_5k = report.Indicators[10],
                        C_5l = report.Indicators[11],
                        C_5m = report.Indicators[12],
                        C_5n = report.Indicators[13],
                        C_5o = report.Indicators[14],
                        C_5p = report.Indicators[15],
                        C_5q = report.Indicators[16],
                        C_5x = report.Indicators[17],
                        C_5y = report.Indicators[18]
                    };
                    dbContext.ANCForm_PMTCT.Add(sectionInfo);
                    form.ANCForm_PMTCT = sectionInfo;
                }

                if (report.SectionNumber == MTUHA_REPORT_SECTION_6)
                {
                    var sectionInfo = new ANCForm_Malaria
                    {
                        ANCFormMetadata = metadata,
                        Facility = dbContext.Facilities.Where(f => f.FacCode == this.facilityCode).FirstOrDefault(),
                        ReportDate = DateTime.Parse(string.Format("{0}-{1}-1", this.reportYear, this.reportMonth)),
                        LessThan20 = (report.AgeCategory == MTUHAAgeCategory.UNDER_20_YEARS),

                        C_6a = report.Indicators[0],
                        C_6b = report.Indicators[1],
                        C_6c = report.Indicators[2],
                        C_6d = report.Indicators[3],
                        C_6e = report.Indicators[4]
                    };
                    dbContext.ANCForm_Malaria.Add(sectionInfo);
                    form.ANCForm_Malaria = sectionInfo;
                }
            }

            int savedObjects = 0;
            try
            {
                savedObjects = dbContext.SaveChanges();
                var r = ReportingError.GetReportingError(error, PhoneNumber);
                r.ErrorText = string.Format("{0} {1} {2}: {3}",
                        Keyword, Utilities.GetMonthText(ReportMonth, true), ReportYear, r.ErrorText);
                this.reportingError = r;
            }
            catch (Exception ex)
            {
                Utilities.LogError(ex, null);
                var r = new ReportingError
                {
                    Code = ReportingError.INVALID_OBJECT_LABEL,
                    KnownError = false,
                    ErrorText = "Fatal error occured during saving the report." +
                        " Report this error to development team for resolution.",
                    Type = ReportProcessingError.INVALID_OBJECT
                };
                this.reportingError = r;
            }

            return (savedObjects > 0);
        }

        protected override bool Update(ReportDataSegment report, ANCFormMetadata metadata)
        {

            ANCForm form = GetRootANCForm(report, metadata);
            bool lessThan20 = (report.AgeCategory == MTUHAAgeCategory.UNDER_20_YEARS);

            bool found = false;
            switch (report.SectionNumber)
            {
                case MTUHA_REPORT_SECTION_1:
                    found = true;
                    form.C_1 = report.Indicators[0];
                    break;

                case MTUHA_REPORT_SECTION_3:
                    found = true;
                    form.C_3 = report.Indicators[0];
                    break;

                case MTUHA_REPORT_SECTION_7:
                    found = true;
                    form.C_7 = report.Indicators[0];
                    break;

                case MTUHA_REPORT_SECTION_8:
                    found = true;
                    form.C_8 = report.Indicators[0];
                    break;

                case MTUHA_REPORT_SECTION_9:
                    found = true;
                    form.C_9 = report.Indicators[0];
                    break;

                case MTUHA_REPORT_SECTION_10:
                    found = true;
                    form.C_10 = report.Indicators[0];
                    break;
            }

            if (found) form.ANCFormMetadata = metadata;
            else
            {
                string info = "== UPDATING NON-EXISTING REPORT SEGMENT ==" + Environment.NewLine
                            + "Reporting date: " + string.Format("{0:ddd, dd MMM yyyy hh:mm tt}", metadata.TimeReceived) + Environment.NewLine
                            + "Facility: " + this.userFacility.FacCode + " - " + this.userFacility.FacName + Environment.NewLine
                            + "Report Month: " + this.reportMonth + ", Report Year: " + this.reportYear + Environment.NewLine
                            + "Text Message: " + this.message;

                if (report.SectionNumber == MTUHA_REPORT_SECTION_2)
                {
                    var sectionInfo = (from s in dbContext.ANCForm_HudhurioLaKwanza
                                       where s.FacilityCode == this.facilityCode
                                           && s.LessThan20 == lessThan20
                                           && s.Year == this.reportYear
                                           && s.Month == this.reportMonth
                                       select s).SingleOrDefault();

                    if (sectionInfo == null)
                    {
                        var exception = new Exception(info);
                        Utilities.LogError(exception, null);
                        return false;
                    }

                    metadata.PreviousReportId = sectionInfo.Id;
                    sectionInfo.ANCFormMetadata = metadata;
                    sectionInfo.C_2a = report.Indicators[0];
                    sectionInfo.C_2b = report.Indicators[1];
                    sectionInfo.C_2c = report.Indicators[2];
                    sectionInfo.C_2d = report.Indicators[3];
                    sectionInfo.C_2e = report.Indicators[4];
                    sectionInfo.C_2f = report.Indicators[5];
                    sectionInfo.C_2g = report.Indicators[6];
                }

                if (report.SectionNumber == MTUHA_REPORT_SECTION_4)
                {
                    var sectionInfo = (from s in dbContext.ANCForm_VidokezoVyaHatari
                                       where s.FacilityCode == this.facilityCode
                                           && s.LessThan20 == lessThan20
                                           && s.Year == this.reportYear
                                           && s.Month == this.reportMonth
                                       select s).SingleOrDefault();

                    if (sectionInfo == null)
                    {
                        var exception = new Exception(info);
                        Utilities.LogError(exception, null);
                        return false;
                    }

                    metadata.PreviousReportId = sectionInfo.Id;
                    sectionInfo.ANCFormMetadata = metadata;
                    sectionInfo.C_4a = report.Indicators[0];
                    sectionInfo.C_4b = report.Indicators[1];
                    sectionInfo.C_4c = report.Indicators[2];
                    sectionInfo.C_4d = report.Indicators[3];
                    sectionInfo.C_4e = report.Indicators[4];
                    sectionInfo.C_4f = report.Indicators[5];
                    sectionInfo.C_4g = report.Indicators[6];
                    sectionInfo.C_4h = report.Indicators[7];
                    sectionInfo.C_4i = report.Indicators[8];
                    sectionInfo.C_4j = report.Indicators[9];
                    sectionInfo.C_4k = report.Indicators[10];
                    sectionInfo.C_4l = report.Indicators[11];
                    sectionInfo.C_4m = report.Indicators[12];
                    sectionInfo.C_4n = report.Indicators[13];
                    sectionInfo.C_4o = report.Indicators[14];
                    sectionInfo.C_4p = report.Indicators[15];
                    sectionInfo.C_4q = report.Indicators[16];
                    sectionInfo.C_4r = report.Indicators[17];
                }

                if (report.SectionNumber == MTUHA_REPORT_SECTION_5)
                {
                    var sectionInfo = (from s in dbContext.ANCForm_PMTCT
                                       where s.FacilityCode == this.facilityCode
                                           && s.LessThan20 == lessThan20
                                           && s.Year == this.reportYear
                                           && s.Month == this.reportMonth
                                       select s).SingleOrDefault();

                    if (sectionInfo == null)
                    {
                        var exception = new Exception(info);
                        Utilities.LogError(exception, null);
                        return false;
                    }

                    metadata.PreviousReportId = sectionInfo.Id;
                    sectionInfo.ANCFormMetadata = metadata;
                    sectionInfo.C_5a = report.Indicators[0];
                    sectionInfo.C_5b = report.Indicators[1];
                    sectionInfo.C_5c = report.Indicators[2];
                    sectionInfo.C_5d = report.Indicators[3];
                    sectionInfo.C_5e = report.Indicators[4];
                    sectionInfo.C_5f = report.Indicators[5];
                    sectionInfo.C_5g = report.Indicators[6];
                    sectionInfo.C_5h = report.Indicators[7];
                    sectionInfo.C_5i = report.Indicators[8];
                    sectionInfo.C_5j = report.Indicators[9];
                    sectionInfo.C_5k = report.Indicators[10];
                    sectionInfo.C_5l = report.Indicators[11];
                    sectionInfo.C_5m = report.Indicators[12];
                    sectionInfo.C_5n = report.Indicators[13];
                    sectionInfo.C_5o = report.Indicators[14];
                    sectionInfo.C_5p = report.Indicators[15];
                    sectionInfo.C_5q = report.Indicators[16];
                }

                if (report.SectionNumber == MTUHA_REPORT_SECTION_6)
                {
                    var sectionInfo = (from s in dbContext.ANCForm_Malaria
                                       where s.FacilityCode == this.facilityCode
                                           && s.LessThan20 == lessThan20
                                           && s.Year == this.reportYear
                                           && s.Month == this.reportMonth
                                       select s).SingleOrDefault();

                    if (sectionInfo == null)
                    {
                        var exception = new Exception(info);
                        Utilities.LogError(exception, null);
                        return false;
                    }

                    metadata.PreviousReportId = sectionInfo.Id;
                    sectionInfo.ANCFormMetadata = metadata;
                    sectionInfo.C_6a = report.Indicators[0];
                    sectionInfo.C_6b = report.Indicators[1];
                    sectionInfo.C_6c = report.Indicators[2];
                    sectionInfo.C_6d = report.Indicators[3];
                    sectionInfo.C_6e = report.Indicators[4];
                }
            }

            int savedObjects = 0;
            try
            {
                savedObjects = dbContext.SaveChanges();
                var r = ReportingError.GetReportingError(error, PhoneNumber);
                r.ErrorText = string.Format("{0} {1} {2}: {3}",
                        Keyword, Utilities.GetMonthText(ReportMonth, true), ReportYear, r.ErrorText);
                this.reportingError = r;
            }
            catch (Exception ex)
            {
                Utilities.LogError(ex, null);
                var r = new ReportingError
                {
                    Code = ReportingError.INVALID_OBJECT_LABEL,
                    KnownError = false,
                    ErrorText = "Fatal error occured during saving the report." +
                        " Report this error to development team for resolution.",
                    Type = ReportProcessingError.INVALID_OBJECT
                };
                this.reportingError = r;
            }

            return (savedObjects > 0);
        }

        protected override bool InsertComments(string comments)
        {
            // Is the main exists
            ANCForm mainForm = (from f in dbContext.ANCForms
                               where f.FacilityCode == this.facilityCode
                               && f.LessThan20 == false
                               && f.Year == this.reportYear
                               && f.Month == this.reportMonth
                               select f).SingleOrDefault();

            if (mainForm == null) return false;
            else
            {
                mainForm.Comments = comments;
                dbContext.SaveChanges();
                return true;
            }
        }

        /// <summary>
        /// Returns the root ANC Form which consists of different report sections
        /// </summary>
        /// <param name="report"></param>
        /// <returns></returns>
        private ANCForm GetRootANCForm(ReportDataSegment report, ANCFormMetadata metadata)
        {
            bool lessThan20 = (report.AgeCategory == MTUHAAgeCategory.UNDER_20_YEARS);
            // Is the main exists
            ANCForm mainForm = (from f in dbContext.ANCForms
                                where f.FacilityCode == this.facilityCode
                                && f.LessThan20 == lessThan20
                                && f.Year == this.reportYear
                                && f.Month == this.reportMonth
                                select f).SingleOrDefault();

            if (mainForm == null)
            {
                // It doesn't exist; create its metadata
                mainForm = new ANCForm
                {
                    ANCFormMetadata = metadata,
                    Facility = dbContext.Facilities.Where(f => f.FacCode == this.facilityCode).FirstOrDefault(),
                    ReportDate = DateTime.Parse(string.Format("{0}-{1}-1", this.reportYear, this.reportMonth)),
                    LessThan20 = lessThan20
                };

                dbContext.ANCForms.Add(mainForm);
                dbContext.SaveChanges();
            }

            return mainForm;
        }

        protected override bool IsTheReportPresent(int sectionNumber, MTUHAAgeCategory ageCategory)
        {
            bool lessThan20 = (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS);
            bool found = false;
            switch (sectionNumber)
            {
                case MTUHA_REPORT_SECTION_1:
                    found = (from s in dbContext.ANCForms
                             where s.C_1.HasValue
                                 && s.FacilityCode == this.facilityCode
                                 && s.LessThan20 == lessThan20
                                 && s.Year == this.reportYear
                                 && s.Month == this.reportMonth
                             select s).Count() == 1;
                    break;

                case MTUHA_REPORT_SECTION_2:
                    found = (from s in dbContext.ANCForms
                             where s.HudhurioLaKwanza_2id.HasValue
                                 && s.FacilityCode == this.facilityCode
                                 && s.LessThan20 == lessThan20
                                 && s.Year == this.reportYear
                                 && s.Month == this.reportMonth
                             select s).Count() == 1;
                    break;

                case MTUHA_REPORT_SECTION_3:
                    found = (from s in dbContext.ANCForms
                             where s.C_3.HasValue
                                 && s.FacilityCode == this.facilityCode
                                 && s.LessThan20 == lessThan20
                                 && s.Year == this.reportYear
                                 && s.Month == this.reportMonth
                             select s).Count() == 1;
                    break;

                case MTUHA_REPORT_SECTION_4:
                    found = (from s in dbContext.ANCForms
                             where s.VidokezoVyaHatari_4id.HasValue
                                 && s.FacilityCode == this.facilityCode
                                 && s.LessThan20 == lessThan20
                                 && s.Year == this.reportYear
                                 && s.Month == this.reportMonth
                             select s).Count() == 1;
                    break;

                case MTUHA_REPORT_SECTION_5:
                    found = (from s in dbContext.ANCForms
                             where s.PMTCT_5id.HasValue
                                 && s.FacilityCode == this.facilityCode
                                 && s.LessThan20 == lessThan20
                                 && s.Year == this.reportYear
                                 && s.Month == this.reportMonth
                             select s).Count() == 1;
                    break;

                case MTUHA_REPORT_SECTION_6:
                    found = (from s in dbContext.ANCForms
                             where s.Malaria_6id.HasValue
                                 && s.FacilityCode == this.facilityCode
                                 && s.LessThan20 == lessThan20
                                 && s.Year == this.reportYear
                                 && s.Month == this.reportMonth
                             select s).Count() == 1;
                    break;

                case MTUHA_REPORT_SECTION_7:
                    found = (from s in dbContext.ANCForms
                             where s.C_7.HasValue
                                 && s.FacilityCode == this.facilityCode
                                 && s.LessThan20 == lessThan20
                                 && s.Year == this.reportYear
                                 && s.Month == this.reportMonth
                             select s).Count() == 1;
                    break;

                case MTUHA_REPORT_SECTION_8:
                    found = (from s in dbContext.ANCForms
                             where s.C_8.HasValue
                                 && s.FacilityCode == this.facilityCode
                                 && s.LessThan20 == lessThan20
                                 && s.Year == this.reportYear
                                 && s.Month == this.reportMonth
                             select s).Count() == 1;
                    break;

                case MTUHA_REPORT_SECTION_9:
                    found = (from s in dbContext.ANCForms
                             where s.C_9.HasValue
                                 && s.FacilityCode == this.facilityCode
                                 && s.LessThan20 == lessThan20
                                 && s.Year == this.reportYear
                                 && s.Month == this.reportMonth
                             select s).Count() == 1;
                    break;

                case MTUHA_REPORT_SECTION_10:
                    found = (from s in dbContext.ANCForms
                             where s.C_10.HasValue
                                 && s.FacilityCode == this.facilityCode
                                 && s.LessThan20 == lessThan20
                                 && s.Year == this.reportYear
                                 && s.Month == this.reportMonth
                             select s).Count() == 1;
                    break;
            }

            return found;
        }

        protected override int GetReportId()
        {
            var results = from r in dbContext.MTUHA_Reports
                          where r.Name == MTUHA_Reports.ANC_MTUHA_REPORT_VERSION_10_NAME
                          select r.Id;

            int reportId = INVALID_REPORT_ID;
            if (results.Count() == 1) reportId = results.ToList()[0];
            else reportId = INVALID_REPORT_ID;

            return reportId;
        }

        protected override string GetReportKeywords()
        {
            string reportKeywords = GenericTools.Utilities.GetSetting(SETTINGS_KEY_ANC_MTUHA_REPORT_KEYWORDS);
            if (string.IsNullOrEmpty(reportKeywords))
            {
                GenericTools.Utilities.SetSetting(SETTINGS_KEY_ANC_MTUHA_REPORT_KEYWORDS, DEFAULT_ANC_MTUHA_REPORT_KEYWORDS);
                reportKeywords = DEFAULT_ANC_MTUHA_REPORT_KEYWORDS;
            }
            return reportKeywords;
        }

        protected override string GetClassicalReportKeywords()
        {
            string reportKeywords = GenericTools.Utilities.GetSetting(SETTINGS_KEY_CLASSIC_ANC_MTUHA_REPORT_KEYWORDS);
            if (string.IsNullOrEmpty(reportKeywords))
            {
                GenericTools.Utilities.SetSetting(SETTINGS_KEY_CLASSIC_ANC_MTUHA_REPORT_KEYWORDS, DEFAULT_ANC_CLASSIC_MTUHA_REPORT_KEYWORDS);
                reportKeywords = DEFAULT_ANC_CLASSIC_MTUHA_REPORT_KEYWORDS;
            }
            return reportKeywords;
        }

        protected override void IdentifyInvolvedClassicalReportIds()
        {
            if (error == ReportProcessingError.NO_ERROR)
            {
                foreach (var resolvedReport in this.resolvedReports)
                {
                    string settingName = string.Empty;
                    var ageCategory = resolvedReport.AgeCategory;

                    switch (resolvedReport.SectionNumber)
                    {
                        case MTUHA_REPORT_SECTION_1:
                            if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K1_UNDER_20;
                            if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K1_ABOVE_20;
                            break;

                        case MTUHA_REPORT_SECTION_2:
                            if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K2_UNDER_20;
                            if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K2_ABOVE_20;
                            break;

                        case MTUHA_REPORT_SECTION_3:
                            if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K3_UNDER_20;
                            if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K3_ABOVE_20;
                            break;

                        case MTUHA_REPORT_SECTION_4:
                            if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K4_UNDER_20;
                            if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K4_ABOVE_20;
                            break;

                        case MTUHA_REPORT_SECTION_5:
                            if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K5_UNDER_20;
                            if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K5_ABOVE_20;
                            break;

                        case MTUHA_REPORT_SECTION_6:
                            if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K6_UNDER_20;
                            if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K6_ABOVE_20;
                            break;

                        case MTUHA_REPORT_SECTION_7:
                            if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K7_UNDER_20;
                            if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K7_ABOVE_20;
                            break;

                        case MTUHA_REPORT_SECTION_8:
                            if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K8_UNDER_20;
                            if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K8_ABOVE_20;
                            break;

                        case MTUHA_REPORT_SECTION_9:
                            if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K9_UNDER_20;
                            if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K9_ABOVE_20;
                            break;

                        case MTUHA_REPORT_SECTION_10:
                            if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K10_UNDER_20;
                            if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K10_ABOVE_20;
                            break;
                    }

                    string value = Utilities.GetSetting(settingName);
                    if (string.IsNullOrWhiteSpace(value))
                    {
                        var ex = new Exception("Missing matching classical report for ANC section " + resolvedReport.SectionNumber);
                        Utilities.LogError(ex, null);
                        return;
                    }

                    int classicalReportId;
                    bool converted = int.TryParse(value, out classicalReportId);
                    if (converted) this.involvedClassicalReportIds.Add(classicalReportId);
                }
            }
        }

        /// <summary>
        /// Gives the list of saved reports. The list depends on the results of Save method.
        /// If Save method was never called in this instance of validator and return true, then
        /// the value return is null.
        /// Lastly the results are not in-memory data deduced by this instance internal storage.
        /// They fetched directly from the database after changes have been committed.
        /// </summary>
        public List<ANCForm> SavedForms
        {
            get
            {
                if (!savedFormRetrieved)
                {
                    bool under20Found = false;
                    bool above20Found = false;
                    foreach (var g in this.ResolvedReports)
                    {
                        if (g.AgeCategory == MTUHAAgeCategory.UNDER_20_YEARS) under20Found = true;
                        if (g.AgeCategory == MTUHAAgeCategory.ABOVE_20_YEARS) above20Found = true;
                    }

                    if (under20Found && above20Found)
                    {
                        _SavedForms = (from f in dbContext.ANCForms
                                       where f.FacilityCode == this.facilityCode
                                       && f.Year == this.reportYear
                                       && f.Month == this.reportMonth
                                       select f).ToList();
                    }
                    else
                    {
                        bool lessThan20 = default(bool);
                        if (under20Found) lessThan20 = true;
                        if (above20Found) lessThan20 = false;

                        _SavedForms = (from f in dbContext.ANCForms
                                       where f.FacilityCode == this.facilityCode
                                       && f.LessThan20 == lessThan20
                                       && f.Year == this.reportYear
                                       && f.Month == this.reportMonth
                                       select f).ToList();
                    }
                }
                return _SavedForms;
            }
        }

        /// <summary>
        /// This function validates the report section against the set of rules.
        /// if the report is valid, its classical format is saved right away.
        /// </summary>
        /// <param name="reportDataSegment"></param>
        /// <param name="hasError"></param>
        private void ValidateReportSection(ReportDataSegment reportDataSegment, out bool hasError)
        {
            hasError = false;
            string settingName = string.Empty;
            var ageCategory = reportDataSegment.AgeCategory;

            switch (reportDataSegment.SectionNumber)
            {
                case MTUHA_REPORT_SECTION_1:
                    if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K1_UNDER_20;
                    if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K1_ABOVE_20;
                    break;

                case MTUHA_REPORT_SECTION_2:
                    if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K2_UNDER_20;
                    if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K2_ABOVE_20;
                    break;

                case MTUHA_REPORT_SECTION_3:
                    if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K3_UNDER_20;
                    if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K3_ABOVE_20;
                    break;

                case MTUHA_REPORT_SECTION_4:
                    if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K4_UNDER_20;
                    if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K4_ABOVE_20;
                    break;

                case MTUHA_REPORT_SECTION_5:
                    if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K5_UNDER_20;
                    if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K5_ABOVE_20;
                    break;

                case MTUHA_REPORT_SECTION_6:
                    if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K6_UNDER_20;
                    if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K6_ABOVE_20;
                    break;

                case MTUHA_REPORT_SECTION_7:
                    if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K7_UNDER_20;
                    if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K7_ABOVE_20;
                    break;

                case MTUHA_REPORT_SECTION_8:
                    if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K8_UNDER_20;
                    if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K8_ABOVE_20;
                    break;

                case MTUHA_REPORT_SECTION_9:
                    if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K9_UNDER_20;
                    if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K9_ABOVE_20;
                    break;

                case MTUHA_REPORT_SECTION_10:
                    if (ageCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K10_UNDER_20;
                    if (ageCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = MTUHA_ANC_CLASSICAL_K10_ABOVE_20;
                    break;
            }

            string value = Utilities.GetSetting(settingName);
            if (string.IsNullOrWhiteSpace(value))
            {
                var ex = new Exception("Missing matching classical report for ANC section " + reportDataSegment.SectionNumber);
                Utilities.LogError(ex, null);
                return;
            }

            int classicalReportId;
            bool converted = int.TryParse(value, out classicalReportId);
            if (converted)
            {
                var reportData = new List<string>
                {
                    this.facilityCode, 
                    this.reportMonth.ToString(), 
                    this.reportYear.ToString()
                };
                foreach (var i in reportDataSegment.Indicators) reportData.Add(i.ToString());

                CheckAgainstBusinessRules(phoneNumberOrUsername, classicalReportId, reportData, out reportingError);
                
                // We are only interested with report sent with fewer parameter. Could be associated with new tools
                // which have fewer tools. And of course it should be from segment 5 - PMTCT
                if (reportingError.Type == ReportProcessingError.FEW_REPORT_PARAMETERS)
                {
                    if (reportDataSegment.SectionNumber == MTUHA_REPORT_SECTION_5)
                    {
                        string[] settingNames = new string[]
                        {
                            MTUHA_ANC_CLASSICAL_K5_UNDER_20v1,
                            MTUHA_ANC_CLASSICAL_K5_ABOVE_20v1,
                            MTUHA_ANC_CLASSICAL_K5_UNDER_20v2,
                            MTUHA_ANC_CLASSICAL_K5_ABOVE_20v2
                        };

                        int newToolClassicalReportId;
                        settingName = string.Empty;
                        bool firstVersionSelected = false;
                        bool secondVersionSelected = false;
                        for (int i = 0; i < 2; i++)
                        {
                            firstVersionSelected = (i == 0);
                            secondVersionSelected = (i == 1);

                            int baseIndexForSettingName = i * 2;
                            if (reportDataSegment.AgeCategory == MTUHAAgeCategory.UNDER_20_YEARS) settingName = settingNames[baseIndexForSettingName];
                            if (reportDataSegment.AgeCategory == MTUHAAgeCategory.ABOVE_20_YEARS) settingName = settingNames[baseIndexForSettingName + 1];
                            value = Utilities.GetSetting(settingName);

                            converted = int.TryParse(value, out newToolClassicalReportId);
                            if (converted)
                            {
                                // Without forgeting that the number of indicators submitted must match
                                // with this new tools for this report to be considered new.
                                int newToolRequiredParameterCount = GetReportDataParameterCount(newToolClassicalReportId);
                                if (reportData.Count == newToolRequiredParameterCount)
                                {
                                    CheckAgainstBusinessRules(phoneNumberOrUsername, newToolClassicalReportId, reportData, out reportingError);
                                    if ((reportingError.Type != ReportProcessingError.FEW_REPORT_PARAMETERS)
                                        && (reportingError.Type != ReportProcessingError.MANY_REPORT_PARAMETERS))
                                    {
                                        classicalReportId = newToolClassicalReportId;
                                        if (firstVersionSelected)
                                        {
                                            reportDataSegment.Indicators.Add(0);
                                            reportDataSegment.Indicators.Add(0);
                                        }
                                        if (secondVersionSelected)
                                        {
                                            int[] temp = reportDataSegment.Indicators.ToArray();
                                            reportDataSegment.Indicators[4] = 0;   // 5e does not have a match

                                            // From index 5 to 
                                            for (int x = 5; x < 12; x++) reportDataSegment.Indicators[x] = temp[x - 1];
                                            reportDataSegment.Indicators[12] = temp[13];    // 5m
                                            reportDataSegment.Indicators[13] = 0;   // 5n
                                            reportDataSegment.Indicators[14] = 0;   // 5o
                                            reportDataSegment.Indicators.Add(0);    // 5p    
                                            reportDataSegment.Indicators.Add(temp[14]);     // 5x
                                            reportDataSegment.Indicators.Add(temp[11]);     // 5y
                                            reportDataSegment.Indicators.Add(temp[12]);     // 5q
                                        }
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }

                hasError = reportingError.Type != ReportProcessingError.NO_ERROR;
                reportDataSegment.Valid = (reportingError.Type == ReportProcessingError.NO_ERROR);
                if (!hasError)
                {
                    SaveReportInClassicalFormat(classicalReportId, reportData);
                }
            }
        }
    }
}
